package com.xstudio.pvzreborn.item;

import com.xstudio.pvzreborn.PVZReborn;
import com.xstudio.pvzreborn.block.BlockManager;
import com.xstudio.pvzreborn.block.BlockNames;
import com.xstudio.pvzreborn.entity.entities.plant.EntityPlantWallNut;
import com.xstudio.pvzreborn.event.custom.PVZRegistryEvent;
import com.xstudio.pvzreborn.event.custom.PVZRegistryEvent.Kind;
import com.xstudio.pvzreborn.item.armor.NaturalDiamondArmor;
import com.xstudio.pvzreborn.item.armor.PVZArmorMaterial;
import com.xstudio.pvzreborn.item.armor.PhotovoltaicAlloyArmor;
import com.xstudio.pvzreborn.utils.registry.ItemRegistrationHelper;
import com.xstudio.pvzreborn.utils.registry.RegistrationAction;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.item.ArmorMaterials;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Item.Properties;
import net.minecraft.world.item.ItemNameBlockItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegistryObject;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public class ItemManager {

	public static final DeferredRegister<Item> ITEM_REGISTRY = DeferredRegister.create(ForgeRegistries.ITEMS, PVZReborn.MOD_ID);
	private static final Map<String, List<String>> TEXTURE_GROUPS = new HashMap<>();
	private static final Map<String, RegistryObject<? extends Item>> ITEMS = new HashMap<>();
	private static final Map<RegistryObject<? extends Item>, String> ITEM_JEI_DESC = new HashMap<>();
	private static final RegistrationAction<Properties, Item> defaultRegistryAction = (itemName, properties) -> () -> new PVZItemBase(itemName);

	/**
	 * @author Bread_NiceCat
	 */
	public static void init(IEventBus bus) {
		PVZReborn.LOGGER.info("Initializing items");
		ITEM_REGISTRY.register(bus);
		bus.addGenericListener(Item.class, ItemManager::onPVZItemRegistering);
		registerArmors();
		registerGeneticItems();
		registerTestTubeItems();
		registerSeedPackets();
		registerPolarDyes();
		registerMiscItems();
		registerFruit();
		registerCoin();
		PVZReborn.LOGGER.info("Initialized items");
	}

	public static void onPVZItemRegistering(PVZRegistryEvent.Post<Item> event) {
		String itemName = event.getName();
		String textureGroup = event.getTextureGroup();
		RegistryObject<? extends Item> object = event.getObject();

		ITEMS.put(itemName, object);
		ITEM_JEI_DESC.put(object, (event.getKind() == Kind.BlockItem ? "block." : "item.") + PVZReborn.MOD_ID + "." + itemName + ".jei.desc");
		if (textureGroup != null) {
			TEXTURE_GROUPS.computeIfAbsent(textureGroup, (key) -> new ArrayList<>()).add(itemName);
		}
	}

	/**
	 * @author superhelo
	 */
	@NotNull
	public static Item getItem(String name) {
		return Objects.requireNonNull(ITEMS.get(name), "Unable to load item::" + name).get();
	}

	@NotNull
	public static ItemStack getDefaultItemStack(String name) {
		return getItem(name).getDefaultInstance();
	}

	/**
	 * @author Bread_NiceCat
	 */
	public static Map<String, List<String>> getTextureGroups() {
		return TEXTURE_GROUPS;
	}

	/**
	 * @author Bread_NiceCat
	 */
	public static Map<RegistryObject<? extends Item>, String> getJEIDescs() {
		return ITEM_JEI_DESC;
	}

	private static void registerGeneticItems() {
		new ItemRegistrationHelper("genetic", defaultRegistryAction)
				.addElement(ItemNames.DARK_KNIGHT_SWORD)
				.addElement(ItemNames.SUPERCRITICAL_FIRE)
				.addElement(ItemNames.EIGHTEENTH_STATE_ICE)
				.addElement(ItemNames.ANCIENT_EYE)
				.addElement(ItemNames.OVERLOADED_REDSTONE)
				.addElement(ItemNames.REDSTONE_ARM)
				.addElement(ItemNames.HUGE_PEA)
				.addElement(ItemNames.BEDROCK_DUST)
				.addElement(ItemNames.CREEPER_GLAND)
				.addElement(ItemNames.SHARP_ENDER_CRYSTAL_SHARD)
				.addElement(ItemNames.ENTITY_LIGHT)
				.addElement(ItemNames.IRON_GOLEM_SCULPTURE_SHARD)
				.addElement(ItemNames.COMPACT_THALLIUM_SULFATE)
				.addElement(ItemNames.UNCONTROLLABLE_NETHER_STAR, (itemName, properties) -> UncontrollableNetherStar::new)
				.register();
	}

	private static void registerTestTubeItems() {
		new ItemRegistrationHelper("test_tube", defaultRegistryAction)
				.addElement(ItemNames.EMPTY_TEST_TUBE)
				.addElement(ItemNames.WARPED_WART_TEST_TUBE)
				.addElement(ItemNames.AID_TEST_TUBE)
				.addElement(ItemNames.CONTROL_TEST_TUBE)
				.addElement(ItemNames.EXPLOSION_TEST_TUBE)
				.addElement(ItemNames.FIRE_TEST_TUBE)
				.addElement(ItemNames.ICE_TEST_TUBE)
				.addElement(ItemNames.MAGIC_TEST_TUBE)
				.addElement(ItemNames.MECHANICAL_TEST_TUBE)
				.addElement(ItemNames.POISON_TEST_TUBE)
				.addElement(ItemNames.PROPELLANT_TEST_TUBE)
				.addElement(ItemNames.SHARPNESS_TEST_TUBE)
				.addElement(ItemNames.SUNSHINE_TEST_TUBE)
				.addElement(ItemNames.THUNDER_TEST_TUBE)
				.addElement(ItemNames.WARRIOR_TEST_TUBE)
				.addElement(ItemNames.DARKNESS_TEST_TUBE)
				.register();
	}

	private static void registerSeedPackets() {
		new ItemRegistrationHelper("seed_packet", defaultRegistryAction)
				.addElement(ItemNames.WHITE_SEED_PACKET)
				.addElement(ItemNames.GREEN_SEED_PACKET)
				.addElement(ItemNames.BLUE_SEED_PACKET)
				.addElement(ItemNames.PURPLE_SEED_PACKET)
				.addElement(ItemNames.GOLDEN_SEED_PACKET)
				.addElement(ItemNames.RED_SEED_PACKET)
				.addElement(ItemNames.WALLNUT_SEED_PACKET, (itemName, properties) -> () -> new PVZPlantSeedPacketItem(itemName, EntityPlantWallNut.NAME, 50, 30))
				.register();
	}

	private static void registerPolarDyes() {
		new ItemRegistrationHelper("polar_dye", defaultRegistryAction)
				.addElement(ItemNames.WHITE_POLAR_DYE)
				.addElement(ItemNames.GREEN_POLAR_DYE)
				.addElement(ItemNames.BLUE_POLAR_DYE)
				.addElement(ItemNames.PURPLE_POLAR_DYE)
				.addElement(ItemNames.GOLDEN_POLAR_DYE)
				.addElement(ItemNames.RED_POLAR_DYE)
				.register();
	}

	private static void registerMiscItems() {
		new ItemRegistrationHelper("misc", defaultRegistryAction)
				.addElement(ItemNames.WISDOM_TREE_ESSENCE)
				.addElement(ItemNames.PHOTOVOLTAIC_ALLOY)
				.addElement(ItemNames.NATURAL_DIAMOND)
				.addElement(ItemNames.RUBY)
				.register();
	}

	private static void registerCoin() {
		new ItemRegistrationHelper("coin")
				.addElement(ItemNames.SLIVER_COIN, (itemName, properties) -> () -> new PVZDaveCoinItem(itemName, 10))
				.addElement(ItemNames.GOLDEN_COIN, (itemName, properties) -> () -> new PVZDaveCoinItem(itemName, 50))
				.addElement(ItemNames.SHINING_DIAMOND, (itemName, properties) -> () -> new PVZDaveCoinItem("diamond", 500))
				.register();
	}

	private static void registerArmors() {
		var naturalDiamond = PVZArmorMaterial.importArmorMaterial(ItemNames.NATURAL_DIAMOND, ArmorMaterials.DIAMOND, null, null, null, null, null, null, () -> Ingredient.of(getItem(ItemNames.NATURAL_DIAMOND)));
		var photovoltaicAlloy = PVZArmorMaterial.registerArmorMaterial(ItemNames.PHOTOVOLTAIC_ALLOY, 44, new int[]{5, 10, 8, 5}, 10, SoundEvents.ARMOR_EQUIP_NETHERITE, 3.5f, 0.2f, () -> Ingredient.of(getItem(ItemNames.PHOTOVOLTAIC_ALLOY)));
		new ItemRegistrationHelper("armor", true)
				.addElement(ItemNames.NATURAL_DIAMOND_HELMET, armorAction(naturalDiamond, EquipmentSlot.HEAD, NaturalDiamondArmor::new))
				.addElement(ItemNames.NATURAL_DIAMOND_CHESTPLATE, armorAction(naturalDiamond, EquipmentSlot.CHEST, NaturalDiamondArmor::new))
				.addElement(ItemNames.NATURAL_DIAMOND_LEGGINGS, armorAction(naturalDiamond, EquipmentSlot.LEGS, NaturalDiamondArmor::new))
				.addElement(ItemNames.NATURAL_DIAMOND_BOOTS, armorAction(naturalDiamond, EquipmentSlot.FEET, NaturalDiamondArmor::new))
				.addElement(ItemNames.PHOTOVOLTAIC_ALLOY_HELMET, armorAction(photovoltaicAlloy, EquipmentSlot.HEAD, PhotovoltaicAlloyArmor::new))
				.addElement(ItemNames.PHOTOVOLTAIC_ALLOY_CHESTPLATE, armorAction(photovoltaicAlloy, EquipmentSlot.CHEST, PhotovoltaicAlloyArmor::new))
				.addElement(ItemNames.PHOTOVOLTAIC_ALLOY_LEGGINGS, armorAction(photovoltaicAlloy, EquipmentSlot.LEGS, PhotovoltaicAlloyArmor::new))
				.addElement(ItemNames.PHOTOVOLTAIC_ALLOY_BOOTS, armorAction(photovoltaicAlloy, EquipmentSlot.FEET, PhotovoltaicAlloyArmor::new))
				.register();
	}

	private static void registerFruit() {
		var action = foodAction(1, 0);
		var action1 = cropAction(1, 0);
		var action2 = foodAction(1, 1);
		new ItemRegistrationHelper("fruit")
				.addElement(BlockNames.CABBAGE, action1)
				.addElement(BlockNames.CATTAIL, action1)
				.addElement(ItemNames.CHERRY, action)
				.addElement(BlockNames.CLOVER, action1)
				.addElement(BlockNames.GARLIC, action1)
				.addElement(ItemNames.MARIGOLD, action)
				.addElement(ItemNames.TURNIP, action)
				.addElement(ItemNames.CORN, action2)
				.addElement(ItemNames.PEAPOD, action2)
				.addElement(ItemNames.SQUASH, foodAction(1, 4))
				.addElement(ItemNames.STARFRUIT, foodAction(1, 4))
				.addElement(ItemNames.KASUALIX_POTATO, (itemName, properties) -> KasualixPotato::new)
				.addElement(ItemNames.NUT, foodAction(1, 5.5f))
				.addElement(ItemNames.PEPPER, foodAction(1, 3))
				.addElement(ItemNames.PEA, (itemName, properties) ->
						() -> new ItemNameBlockItem(BlockManager.getBlock(BlockNames.PEA_SEEDLINGS), properties.food(builder(1, 0.5f).build())))
				.addElement(ItemNames.TOXICSHROOM, (itemName, properties) -> {
					FoodProperties foodProperties = builder(1, 0)
							.effect(() -> new MobEffectInstance(MobEffects.POISON, 400, 0), 0.8f)
							.build();
					return () -> new PVZItemBase(itemName, properties.food(foodProperties));
				})
				.addElement(ItemNames.CHOMPER, (itemName, properties) -> {
					FoodProperties foodProperties = builder(1, 0)
							.effect(() -> new MobEffectInstance(MobEffects.CONFUSION, 200, 0), 0.5f)
							.effect(() -> new MobEffectInstance(MobEffects.HUNGER, 200, 0), 0.5f)
							.build();
					return () -> new PVZItemBase(itemName, properties.food(foodProperties));
				})
				.register();
	}

	private static FoodProperties.Builder builder(int nutrition, float saturationModifier) {
		return new FoodProperties.Builder().nutrition(nutrition).saturationMod(saturationModifier);
	}

	private static RegistrationAction<Properties, Item> foodAction(int nutrition, float saturationModifier) {
		return (itemName, properties) -> () -> new PVZItemBase(itemName, properties.food(builder(nutrition, saturationModifier).build()));
	}

	private static RegistrationAction<Properties, Item> cropAction(int nutrition, float saturationModifier) {
		return (itemName, properties) -> () -> new ItemNameBlockItem(BlockManager.getBlock(itemName), properties.food(builder(nutrition, saturationModifier).build()));
	}

	private static RegistrationAction<Properties, Item> armorAction(PVZArmorMaterial material, EquipmentSlot slot, java.util.function.BiFunction<com.xstudio.pvzreborn.item.armor.PVZArmorMaterial, net.minecraft.world.entity.EquipmentSlot, ? extends com.xstudio.pvzreborn.item.armor.PVZArmorItemBase> function) {
		return (itemName, properties) -> () -> function.apply(material, slot);
	}

}
